package ie.dit.reg08.realiser;

import ie.dit.reg08.manager.*;

import java.util.Hashtable;
import java.util.Iterator;
import java.util.Vector;

// A class which generates a sentence to describe an object based on attribute-value 
// pairs describing that object and a case base of previous human-generated descriptions
public class CaseBasedSentenceGenerator implements greInterface {

	// The case base
	private Vector<Trial> vTrials;
	private Trial testTrial;
	private String wordString;
	private int matchCountPreFinesse;
	private int matchCountPostFinesse;
	private int bestSentenceFrequency;
	
	public CaseBasedSentenceGenerator(Vector<Trial> v, Trial t){
		vTrials = v;
		testTrial = t;
		
		wordString = this.generateSentence();
	}
	
	// Based on a set of attribute-value pairs this method finds those cases that are an exact match
	private Vector<Trial> findExactAttrbiuteValueMatches(Hashtable<String, String> attributeValuePairs){
		
		Vector<Trial> matches = new Vector<Trial>();
		
		// Cycle through each trial and find all of those that are a match for our set of attribute-value pairs
		Iterator<Trial> j = vTrials.iterator();
		Trial t;
		while(j.hasNext()) {
			t = j.next();
			
			// Obtain the attribute-value pairs describing the description for this this trial
			AttributeSet description = t.getDescription();
			Hashtable<String, String> descAttributeValuePairs = description.getHashtableDescription();
			
			// If the query map and the map in this trial are the same - then bingo add it to the list of matches!
			if(descAttributeValuePairs.equals(attributeValuePairs)){
				
				// Only do this if the query and the case do not have the same ID - for fudgy testing!!!
				if(!(t.getID().equalsIgnoreCase(testTrial.getID()))){
					matches.add(t);
				}
			}
		}
		
		matchCountPreFinesse = matches.size();
		
		return matches;
	}
	
	// From a list of possible matches only keep those ones where the image file name is also the same
	private Vector<Trial> finessMatchesBasedOnImage(Vector<Trial> matches, String imageName){
		
		Vector<Trial> finessedMatches = new Vector<Trial>();
		
		// Cycle through each trial and find all of those that are a match for our set of attribute-value pairs
		Iterator<Trial> j = matches.iterator();
		Trial t;
		while(j.hasNext()) {
			t = j.next();
			
			if(t.getDomain().getTarget().getImageFileName().equalsIgnoreCase(imageName)){
				finessedMatches.add(t);
			}
		}
	
		return finessedMatches;
	}
	
	public String generateSentence(){
		return generateSentence(testTrial.getDescription().getHashtableDescription(), testTrial.getDomain().getTarget().getImageFileName());
	}
	
	public String generateSentence(Hashtable<String, String> attributeValuePairs, String imageName){
		
		Vector<Trial> finessedMatches = new Vector<Trial>();
		Vector<Trial> matches = new Vector<Trial>();
		String sentence;
		
		// find all of the exact matches to the attribute-value pairs
		matches =  findExactAttrbiuteValueMatches(attributeValuePairs);
		
		// If we have only one match just use it
		if(matches.size() == 1){
			sentence = matches.get(0).getWordString();
		
		// If we have more than one match, refine the list a bit 
		}else if(matches.size() > 1){
			// first refine based on only keeping those trials based on the same image
			finessedMatches = finessMatchesBasedOnImage(matches, imageName);
			matchCountPostFinesse = finessedMatches.size();
			
			if(finessedMatches.size() > 0){
				matches = finessedMatches;
			}
			
			
			
			// Next refine by selecting the sentence that appears most times in the list - if they are all
			// equally frequent pick the shortest one
			sentence = pickBestSentenceFromMatchList(matches);
			
		}else{
			sentence = "No idea!!!";
		}
		
		return sentence;
	}
	
	// From a list of possible sentences loop through it and find the sentence that appears most times
	// If there are no duplicates, or there is a tie, use the shortest sentences
	private String pickBestSentenceFromMatchList(Vector<Trial> matches){
		String sentence = "";
		int maxSentenceFrequencyCount = 0;
		String mostFrequentSentence = "";
		
		Iterator<Trial> matchIter = matches.iterator();
		Trial currentTrial;
		while(matchIter.hasNext()) {
			currentTrial = matchIter.next();
			
			int currentSentenceFrequencyCount = 0;
			Iterator<Trial> testIter = matches.iterator();
			Trial currentTestTrial;
			while(testIter.hasNext()) {
				currentTestTrial = testIter.next();
				if(currentTrial.getWordString().equalsIgnoreCase(currentTestTrial.getWordString())){
					currentSentenceFrequencyCount++;
				}
			}
			
			if(currentSentenceFrequencyCount > maxSentenceFrequencyCount){
				maxSentenceFrequencyCount = currentSentenceFrequencyCount;
				mostFrequentSentence = currentTrial.getWordString();
			}
		}
		
		bestSentenceFrequency = maxSentenceFrequencyCount;
		return mostFrequentSentence;
	}
	

	public Vector<String> generateSentences(Hashtable<String, String> attributeValuePairs, String imageName){
		
		Vector<Trial> finessedMatches = new Vector<Trial>();
		Vector<Trial> matches = new Vector<Trial>();
		Vector<String> sentences = new Vector<String>();
		
		// find all of the exact matches to the attribute-value pairs
		matches =  findExactAttrbiuteValueMatches(attributeValuePairs);
		
		// If we have more than one match, refine this list based on the image name
		if(matches.size() == 1){
			sentences.add(matches.get(0).getWordString());
		
		}else if(matches.size() > 1){
			finessedMatches = finessMatchesBasedOnImage(matches, imageName);
			if(finessedMatches.size() > 0){
				matches = finessedMatches;
			}
			
			Iterator<Trial> j = matches.iterator();
			Trial t;
			while(j.hasNext()) {
				t = j.next();
				sentences.add(t.getWordString());
			}
			
		}else{
			sentences.add("No idea!!!");
		}
		
		return sentences;
	}

	public Hashtable<String, String> getDescripton() {
		// TODO Auto-generated method stub
		return null;
	}
	
	public String getID() {
		
		return testTrial.getID();
	}
	
	// Generate an xml version of the resulting sentence containing just the id and the sentence itself
	public String xmlDescription() {
		
		if(wordString.startsWith("No ")){
			System.out.println("!!!!!We missed one : " + getID());
		}else{
			System.out.println(wordString + "[" + matchCountPreFinesse + "|" + matchCountPostFinesse + "|" + bestSentenceFrequency + "]");
		}
		
		StringBuffer xmlString = new StringBuffer("");
		xmlString.append("<TRIAL ID=\"" + getID() + "\">\n");
		xmlString.append("\t<WORD-STRING>" + wordString + "</WORD-STRING>\n");
		xmlString.append("</TRIAL>\n");
		
		return xmlString.toString();
	}
}
